package com.awx.server.registration;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;

import com.awx.server.properties.PropertiesUtils;
import com.awx.server.service.AwxService;
import com.awx.server.service.AwxServiceImpl;
import com.awx.server.xml.XmlUtils;

/**
 * Util for registering Spring Http services into the Ioc xml
 *
 * @author Matias Leone
 *
 */
public abstract class AwxServiceRegistration {

	private final static String CLIENT_XML_PROP = "remoting.client.xml.path";
	private final static String SERVER_XML_PROP = "remoting.server.xml.path";
	private final static String BASE_URL_PROP = "remoting.base.url";

	private List<AwxServiceInfo> infoServices;
	private String baseUrl;
	private String clientXmlPath;
	private String serverXmlPath;
	private String properyFilePath;

	public AwxServiceRegistration() {
		this.infoServices = new ArrayList<AwxServiceInfo>();
		this.loadProperties();
	}

	/**
	 * Load properties for properties file
	 */
	private void loadProperties() {
		this.properyFilePath = this.getProperyFilePath();
		
		Properties props = PropertiesUtils.getPropertiesFile( this.properyFilePath );
		this.clientXmlPath = props.getProperty( CLIENT_XML_PROP );
		this.serverXmlPath = props.getProperty( SERVER_XML_PROP );
		this.baseUrl = props.getProperty( BASE_URL_PROP );
	}

	/**
	 * Register a new service
	 * @param serviceName: name of the service to be invoked later. It is also the url of the service
	 * @param serviceInterface: interface of the service
	 * @param serviceImpl: implementation of the service
	 */
	protected void addService( String serviceName, Class<? extends AwxService> serviceInterface, Class<? extends AwxServiceImpl> serviceImpl ) {
		this.infoServices.add( new AwxServiceInfo( serviceName, serviceInterface, serviceImpl, this.baseUrl ) );
	}

	/**
	 * Register all the services of the aplication.
	 * Example: <code>this.addService( "MyService", MyService.class, MyServiceImpl.class );<code>
	 */
	protected abstract void registerServices();


	/**
	 * Update the client and the server Ioc xml
	 */
	public void buildRegistration() {
		System.out.println( "Updating services xml..." );
		this.registerServices();
		this.updateServerXml();
		this.updateClientXml();
		System.out.println( "Update finished!" );
	}

	/**
	 * Update the server xml with the registered services
	 */
	private void updateServerXml() {
		//load document
		Document documentServer = XmlUtils.loadDocument( serverXmlPath, false );

		//remove all beans from the root
		Element root = documentServer.getRootElement();
		root.removeChildren( AwxServiceInfo.BEAN_TAG_NAME, Namespace.getNamespace( AwxServiceInfo.SPRING_NAMESPACE ) );

		//add services bean
		Element beans[];
		for (AwxServiceInfo info : this.infoServices) {
			beans = info.buildBeansServer();
			for (int i = 0; i < beans.length; i++) {
				root.addContent( beans[ i ] );
			}
		}

		//save document
		XmlUtils.saveDocument( documentServer, this.serverXmlPath );
	}

	/**
	 * Update the client xml with the registered services
	 */
	private void updateClientXml() {
		//load document
		Document documentClient = XmlUtils.loadDocument( clientXmlPath, false );

		//remove all beans from the root
		Element root = documentClient.getRootElement();
		root.removeChildren( AwxServiceInfo.BEAN_TAG_NAME, Namespace.getNamespace( AwxServiceInfo.SPRING_NAMESPACE ) );

		//add services bean
		Element bean;
		for (AwxServiceInfo info : this.infoServices) {
			bean = info.buildBeanClient();
			root.addContent( bean );
		}

		//save document
		XmlUtils.saveDocument( documentClient, this.clientXmlPath );
	}


	/**
	 * Setup the path of the properties file
	 * @return path of the properties file
	 */
	protected abstract String getProperyFilePath();


}














